/*
 *
 * Copyright (c) 2025 Bocloud Technologies Co., Ltd.
 * installer is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain n copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 *
 */
package phases

import (
	"context"
	"fmt"
	"testing"
	"time"

	confv1beta1 "gopkg.openfuyao.cn/bkecommon/cluster/api/v1beta1"
	bkenode "gopkg.openfuyao.cn/bkecommon/cluster/node"
	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"gopkg.openfuyao.cn/cluster-api-provider-bke/api/v1beta1"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/testutils"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/config"
	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/label"
)

const (
	testNodeName       = "test-node-1"
	testNodeIP         = "127.0.0.1"
	testSkipNodeIP     = "127.0.0.2"
	kubeletVersion     = "v1.24.1"
	kubeSystemNS       = "kube-system"
	managementAdminSec = "management-admin"
	testToken          = "test-token"
)

// createRunningPod 创建处于运行状态的测试 Pod
func createRunningPod(name, namespace string) corev1.Pod {
	return corev1.Pod{
		ObjectMeta: v1.ObjectMeta{
			Name:      name,
			Namespace: namespace,
		},
		Status: corev1.PodStatus{
			Phase: corev1.PodRunning,
			Conditions: []corev1.PodCondition{
				{Type: corev1.PodReady, Status: corev1.ConditionTrue},
			},
		},
	}
}

// createTestNodeList 创建测试节点列表
func createTestNodeList() *corev1.NodeList {
	return &corev1.NodeList{
		Items: []corev1.Node{
			{
				ObjectMeta: v1.ObjectMeta{
					Name: testNodeName,
					Labels: map[string]string{
						corev1.LabelHostname:      testNodeName,
						label.NodeRoleMasterLabel: "",
					},
				},
				Status: corev1.NodeStatus{
					NodeInfo: corev1.NodeSystemInfo{
						KubeletVersion: kubeletVersion,
					},
					Addresses: []corev1.NodeAddress{
						{Type: corev1.NodeInternalIP, Address: testNodeIP},
					},
					Conditions: []corev1.NodeCondition{
						{Type: corev1.NodeReady, Status: corev1.ConditionTrue},
					},
				},
			},
		},
	}
}

// createManagementSecret 创建管理员密钥
func createManagementSecret() *corev1.Secret {
	return &corev1.Secret{
		ObjectMeta: v1.ObjectMeta{
			Name:      managementAdminSec,
			Namespace: kubeSystemNS,
		},
		Data: map[string][]byte{
			"token": []byte(testToken),
		},
	}
}

// createServiceAccountList 创建服务账户列表
func createServiceAccountList() *corev1.ServiceAccountList {
	return &corev1.ServiceAccountList{
		Items: []corev1.ServiceAccount{
			{
				ObjectMeta: v1.ObjectMeta{
					Name:      "default",
					Namespace: kubeSystemNS,
				},
			},
		},
	}
}

// createSystemPodList 创建系统组件 Pod 列表
func createSystemPodList() *corev1.PodList {
	return &corev1.PodList{
		Items: []corev1.Pod{
			createRunningPod("kube-apiserver-"+testNodeName, kubeSystemNS),
			createRunningPod("kube-controller-manager-"+testNodeName, kubeSystemNS),
			createRunningPod("kube-scheduler-"+testNodeName, kubeSystemNS),
			createRunningPod("etcd-"+testNodeName, kubeSystemNS),
			createRunningPod("kube-proxy-xxxxx", kubeSystemNS),
			createRunningPod("coredns-xxxxx", kubeSystemNS),
			createRunningPod("calico-kube-controllers-xxxxx", kubeSystemNS),
			createRunningPod("calico-node-xxxxx", kubeSystemNS),
		},
	}
}

// createTestK8sResourceMap 创建测试资源映射
func createTestK8sResourceMap() map[string]interface{} {
	nodeList := createTestNodeList()
	managementSecret := createManagementSecret()
	saList := createServiceAccountList()
	podList := createSystemPodList()

	return map[string]interface{}{
		"/api/v1/nodes": nodeList,
		"/api/v1/namespaces/kube-system/secrets/management-admin":                 managementSecret,
		"/api/v1/namespaces/kube-system/serviceaccounts":                          saList,
		"/api/v1/namespaces/kube-system/pods":                                     podList,
		"/api/v1/namespaces/kube-system/pods/kube-apiserver-test-node-1":          &podList.Items[0],
		"/api/v1/namespaces/kube-system/pods/kube-controller-manager-test-node-1": &podList.Items[1],
		"/api/v1/namespaces/kube-system/pods/kube-scheduler-test-node-1":          &podList.Items[2],
		"/api/v1/namespaces/kube-system/pods/etcd-test-node-1":                    &podList.Items[3],
	}
}

// 初始化测试环境
func initTestPhaseContextWithResources() {
	config.MetricsAddr = "0"

	InitinitPhaseContextFun()

	if initTServer != nil {
		initTServer.Close()
	}

	resourceMap := createTestK8sResourceMap()
	newRestConfig, newTServer := testutils.TestGetK8sServerHttp(resourceMap)

	initRestConfig = newRestConfig
	initTServer = newTServer

	rconfigBytes, _ := testutils.RestConfigToKubeConfig(newRestConfig, "test-context")
	kubeConfigSecret := &corev1.Secret{
		ObjectMeta: v1.ObjectMeta{
			Name:      fmt.Sprintf("%s-kubeconfig", initCluster.Name),
			Namespace: initCluster.Namespace,
		},
		Data: map[string][]byte{
			"value": rconfigBytes,
		},
	}

	_ = initClient.GetClient().Update(context.Background(), kubeConfigSecret)

	if initPhaseContext != nil {
		initPhaseContext.RestConfig = newRestConfig
	}
}

// createTestClusterWithSkipNodes 创建包含跳过节点的测试集群
func createTestClusterWithSkipNodes() *v1beta1.BKECluster {
	nbkec := initNewBkeCluster.DeepCopy()
	nbkec.Status.NodesStatus = confv1beta1.NodesStates{
		{
			Node: confv1beta1.Node{
				IP:       testNodeIP,
				Hostname: "node-skip",
				Role:     []string{bkenode.WorkerNodeRole},
			},
			StateCode: 1,
			NeedSkip:  true,
		},
		{
			Node: confv1beta1.Node{
				IP:       testSkipNodeIP,
				Hostname: "node-check",
				Role:     []string{bkenode.WorkerNodeRole},
			},
			StateCode: 1,
			NeedSkip:  false,
		},
	}
	return nbkec
}

// verifyNodeSkipBehavior 验证节点跳过行为
func verifyNodeSkipBehavior(t *testing.T, cluster *v1beta1.BKECluster) {
	shouldSkip1 := cluster.GetNodeStateNeedSkip(testNodeIP)
	shouldSkip2 := cluster.GetNodeStateNeedSkip(testSkipNodeIP)

	if !shouldSkip1 {
		t.Errorf("Expected node %s to be skipped (needskip=true), "+
			"but GetNodeStateNeedSkip returned false", testNodeIP)
	} else {
		t.Logf("✓ Node %s correctly identified as needing skip", testNodeIP)
	}

	if shouldSkip2 {
		t.Errorf("Expected node %s not to be skipped (needskip=false), "+
			"but GetNodeStateNeedSkip returned true", testSkipNodeIP)
	} else {
		t.Logf("✓ Node %s correctly identified as NOT needing skip", testSkipNodeIP)
	}
}

// TestEnsureClusterBasicExecution 测试基本执行流程
func TestEnsureClusterBasicExecution(t *testing.T) {
	initTestPhaseContextWithResources()

	ec := NewEnsureCluster(initPhaseContext)

	needExec := ec.NeedExecute(&initOldBkeCluster, &initNewBkeCluster)
	t.Logf("NeedExecute returned: %v", needExec)

	if _, err := ec.Execute(); err != nil {
		t.Logf("Execute completed with info: %v", err)
	}
}

// TestEnsureClusterSkipLogic 测试节点跳过逻辑
func TestEnsureClusterSkipLogic(t *testing.T) {
	initTestPhaseContextWithResources()

	nbkec := createTestClusterWithSkipNodes()
	verifyNodeSkipBehavior(t, nbkec)

	initPhaseContext.BKECluster = nbkec
	ec := NewEnsureCluster(initPhaseContext)

	if _, err := ec.Execute(); err != nil {
		t.Logf("Execute completed with info: %v", err)
	}
}

// TestEnsureClusterNilCluster 测试空集群场景
func TestEnsureClusterNilCluster(t *testing.T) {
	initTestPhaseContextWithResources()

	initPhaseContext.Cluster = nil
	ec := NewEnsureCluster(initPhaseContext)
	if _, err := ec.Execute(); err != nil {
		t.Logf("Execute with nil cluster failed (expected): %v", err)
	}
}

// TestEnsureClusterDeletingState 测试删除状态集群
func TestEnsureClusterDeletingState(t *testing.T) {
	initTestPhaseContextWithResources()

	deepBkeCluster := initNewBkeCluster.DeepCopy()
	deepBkeCluster.DeletionTimestamp = &v1.Time{Time: time.Now()}
	deepBkeCluster.Status.ClusterStatus = v1beta1.ClusterDeleting

	initPhaseContext.BKECluster = deepBkeCluster
	ec := NewEnsureCluster(initPhaseContext)

	needExec := ec.NeedExecute(&initOldBkeCluster, deepBkeCluster)
	t.Logf("NeedExecute for deleting cluster returned: %v", needExec)

	if _, err := ec.Execute(); err != nil {
		t.Logf("Execute completed with info: %v", err)
	}
}
